from passlib.context import CryptContext
from datetime import datetime, timedelta
from jose import jwt, JWTError
import asyncio
from functools import partial
from concurrent.futures import ProcessPoolExecutor
import multiprocessing

# rounds=10: 约60ms/次哈希
pwd_context = CryptContext(
    schemes=["bcrypt"],
    deprecated="auto",
    bcrypt__rounds=10
)

SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# ✅ 使用进程池而不是线程池（绕过GIL）
# CPU核心数 × 2，通常8核就是16个进程
_password_executor = ProcessPoolExecutor(
    max_workers=min(16, multiprocessing.cpu_count() * 2)
)

# ========== 独立的哈希函数（必须在模块级别，供pickle序列化）==========
def _hash_password_worker(password: str) -> str:
    """独立的哈希函数，用于进程池"""
    ctx = CryptContext(schemes=["bcrypt"], deprecated="auto", bcrypt__rounds=10)
    return ctx.hash(password)

def _verify_password_worker(plain: str, hashed: str) -> bool:
    """独立的验证函数，用于进程池"""
    ctx = CryptContext(schemes=["bcrypt"], deprecated="auto", bcrypt__rounds=10)
    return ctx.verify(plain, hashed)


def hash_password(password: str) -> str:
    return pwd_context.hash(password)


async def hash_password_async(password: str) -> str:
    """异步版本的密码哈希，使用进程池（绕过GIL）"""
    loop = asyncio.get_event_loop()
    # ✅ 使用进程池，可以真正并行执行bcrypt
    return await loop.run_in_executor(_password_executor, _hash_password_worker, password)


def verify_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)


async def verify_password_async(plain_password: str, hashed_password: str) -> bool:
    """异步版本的密码验证，使用进程池（绕过GIL）"""
    loop = asyncio.get_event_loop()
    # ✅ 使用进程池
    return await loop.run_in_executor(_password_executor, _verify_password_worker, plain_password, hashed_password)


def create_access_token(data: dict, expires_delta: timedelta = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)):
    to_encode = data.copy()
    expire = datetime.utcnow() + expires_delta
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)


def get_current_user_info(request):
    """从 Cookie 解码出当前登录用户信息"""
    token_cookie = request.cookies.get("access_token")
    if not token_cookie:
        return None, None
    try:
        token = token_cookie.split(" ")[1]
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username = payload.get("sub")
        role = payload.get("role", "user")
        if role:
            role = role.strip().lower()
        return username, role
    except JWTError:
        return None, None